﻿using System;
using System.IO.Pipes;
using System.Threading;
using SimplePipeHelper.Common;

namespace SimplePipeHelper.Server
{
    internal class PipeServerReadHelper : IDisposable
    {
        private readonly Action _onPipeClosed; //管道客户端关闭
        private readonly Action<byte[]> _onDataReceived; //管道接收到数据
        private readonly Action<string> _onErrorMessage; //错误信息

        private NamedPipeServerStream _pipeServer;
        private PipeAsyncState _asyncState;
        private readonly int _maxReadBufferSize;
        private readonly MessageHelper _messageHelper;

        private Thread _threadWorker;
        private bool _threadWorking;
        private readonly object _threadWorkingLockHelper = new object();

        private bool IsThreadWorking
        {
            get
            {
                bool ret;
                lock (_threadWorkingLockHelper)
                {
                    ret = _threadWorking;
                }

                return ret;
            }
            set
            {
                lock (_threadWorkingLockHelper)
                {
                    _threadWorking = value;
                }
            }
        }

        public PipeServerReadHelper(
            Action onPipeClosed,
            Action<byte[]> onDataReceived,
            Action<string> onErrorMessage,
            int maxReadBufferSize)
        {
            _onPipeClosed = onPipeClosed;
            _onDataReceived = onDataReceived;
            _onErrorMessage = onErrorMessage;
            _maxReadBufferSize = maxReadBufferSize;

            _messageHelper = new MessageHelper();
        }

        public void Start(NamedPipeServerStream pipeServer)
        {
            _pipeServer = pipeServer;
            if (pipeServer == null)
            {
                return;
            }

            _asyncState = new PipeAsyncState()
            {
                PipeStream = _pipeServer,
                Buffer = new byte[_maxReadBufferSize],
                EventHandle = new ManualResetEvent(false)
            };

            _messageHelper.Start(OnPipeMessage);

            IsThreadWorking = true;
            _threadWorker = new Thread(ReadThreadFunc) {IsBackground = true};
            _threadWorker.Start();
        }

        public void Stop()
        {
            //发送终止信号
            IsThreadWorking = false;
            _asyncState?.SetEvent();

            //终止线程
            _threadWorker?.Join();
            _threadWorker = null;

            //释放同步资源
            _asyncState?.Dispose();
            _asyncState = null;

            _messageHelper.Stop();
        }

        private void OnPipeMessage(byte[] buffer)
        {
            _onDataReceived?.Invoke(buffer);
        }

        private void ReadThreadFunc()
        {
            while (IsThreadWorking)
            {
                if (_pipeServer == null || !_pipeServer.IsConnected || _asyncState?.EventHandle == null)
                {
                    break;
                }

                try
                {
                    _asyncState.ResetEvent();
                    _pipeServer.BeginRead(_asyncState.Buffer, 0,
                        _maxReadBufferSize, OnPipeReadCallback, _asyncState);
                    _asyncState.EventHandle.WaitOne();
                }
                catch (ObjectDisposedException e)
                {
                    _onErrorMessage?.Invoke(e.Message);

                    //管道已关闭
                    _onPipeClosed?.Invoke();
                    break;
                }
                catch (InvalidOperationException e)
                {
                    _onErrorMessage?.Invoke(e.Message);

                    //管道已断开，正在等待连接
                    _onPipeClosed?.Invoke();
                    break;
                }
                catch (Exception e)
                {
                    _onErrorMessage?.Invoke(e.Message);
                    _onPipeClosed?.Invoke();
                    break;
                }
            }
        }

        private void OnPipeReadCallback(IAsyncResult ar)
        {
            var state = (PipeAsyncState) ar.AsyncState;
            if (state == null)
            {
                throw new NullReferenceException();
            }

            if (!state.PipeStream.IsConnected)
            {
                state.SetEvent();
                return;
            }

            var readLength = state.PipeStream.EndRead(ar);
            if (readLength == 0)
            {
                _onPipeClosed?.Invoke();
            }
            else
            {
                var buffer = state.Buffer;
                if (readLength < buffer.Length)
                {
                    buffer = new byte[readLength];
                    Buffer.BlockCopy(state.Buffer, 0, buffer, 0, readLength);
                }

                _messageHelper?.AddMessage(buffer);
            }

            state.SetEvent();
        }

        #region IDisposable Support

        //检测冗余调用
        private bool _disposedValue;

        private void Dispose(bool disposing)
        {
            if (!_disposedValue)
            {
                if (disposing)
                {
                    //释放托管状态(托管对象)。
                    Stop();
                }

                //释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
                //将大型字段设置为 null。

                _disposedValue = true;
            }
        }

        ~PipeServerReadHelper()
        {
            Dispose(false);
        }

        // 添加此代码以正确实现可处置模式。
        void IDisposable.Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion
    }
}
